#include <board.h>

#define APPLICATION_ADDRESS (uint32_t)0x08010000

typedef void (*pFunction)(void);

pFunction JumpToApplication;
uint32_t JumpAddress;

/**
 * @brief  跳转到应用程序（Application）的入口函数
 *
 * @note   该函数用于从 Bootloader 安全跳转到已烧录在指定地址的应用程序。
 *         跳转前需完成中断、堆栈、系统状态的清理与重置，确保 App 能在“干净”的环境中启动。
 *         适用于基于 ARM Cortex-M 系列 MCU 的 Bootloader 设计。
 */
void jump2app(void)
{
    // 1. 获取应用程序的复位向量（即 Reset Handler 地址）
    //    向量表结构：[0] = MSP 初始值，[1] = 复位处理函数地址
    JumpAddress = *(__IO uint32_t *)(APPLICATION_ADDRESS + 4);

    // 将获取到的函数地址强制转换为函数指针类型，便于后续调用
    JumpToApplication = (pFunction)JumpAddress;

    // 2. 关闭全局中断，防止跳转过程中发生中断干扰
    __disable_irq();

    // 3. 禁用并重置 SysTick 定时器
    //    SysTick 是 Cortex-M 内核的系统定时器，常用于 RTOS 或延时
    //    若不清除，可能在跳转后立即触发中断，导致 App 初始化失败
    SysTick->CTRL = 0; // 关闭 SysTick 计数器和中断
    SysTick->LOAD = 0; // 清空重载值
    SysTick->VAL = 0;  // 清空中断计数值

    // 4. 清除所有 NVIC 中断使能和挂起状态
    //    NVIC: Nested Vectored Interrupt Controller（嵌套向量中断控制器）
    //    ICER: Interrupt Clear-Enable Register，用于关闭中断使能
    //    ICPR: Interrupt Clear-Pending Register，用于清除挂起的中断请求
    for (char i = 0; i < 8; i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF; // 关闭所有中断线（共 240 条，8 个 32 位寄存器）
        NVIC->ICPR[i] = 0xFFFFFFFF; // 清除所有挂起的中断（防止跳转后立即响应）
    }
    // 注：实际 MCU 可能只支持部分中断线（如 STM32F1 支持 68 条），但写全更安全

    // 5. 重新开启全局中断（此时无任何中断使能，不会立即触发）
    //    为应用程序启用中断系统做准备
    __enable_irq();

    /* Initialize user application's Stack Pointer */
    // 6. 设置主堆栈指针（MSP）
    //    从应用程序向量表的第一个字（地址 APPLICATION_ADDRESS）读取初始 MSP 值
    //    这是 Cortex-M 启动时的规范：向量表首项必须是栈顶地址
    __set_MSP(*(__IO uint32_t *)APPLICATION_ADDRESS);

    // 7. 设置 CONTROL 寄存器
    //    CONTROL[0] = 0: 使用 MSP（主堆栈指针），而非 PSP（进程堆栈指针）
    //    CONTROL[1] = 0: 运行在特权模式（Privileged Mode）
    //    这确保应用程序从最基础、最安全的运行模式开始
    __set_CONTROL(0);

    // 8. 执行跳转：调用应用程序的 Reset Handler
    //    此时 CPU 将跳转到应用程序的复位处理函数，开始执行 App 的初始化流程
    //    后续控制权完全交给应用程序，Bootloader 不再运行
    JumpToApplication();
}